# Python 命名空间

# 命名空间的概念
# 命名空间是指在一个程序中，不同名称的变量、函数、类、模块等实体之间的关系。
# 命名空间的作用是避免命名冲突，使得不同名称的实体可以互相区分。

# 一般有以下几种命名空间：
# 1. 全局命名空间：全局命名空间是指所有的模块都共享的命名空间，所有的变量、函数、类、模块等实体都在这个命名空间中。
# 2. 局部命名空间：局部命名空间是指函数、模块、类等代码块内部的命名空间，它只对当前代码块有效。
# 3. 内置命名空间：内置命名空间是指 Python 解释器自带的命名空间，它包含了一些内置的函数、模块、类等实体。
# 4. 嵌套命名空间：嵌套命名空间是指函数、模块、类等代码块内部定义的命名空间，它可以包含其他的命名空间。

# 命名空间的查找顺序
# 局部命名空间 -> 全局命名空间 -> 内置命名空间

# 命名空间的生命周期
# 命名空间的生命周期取决于对象的作用域，如果对象执行完成，则该命名空间的生命周期就结束。
# 因此，我们无法从外部命名空间访问内部命名空间的对象


# 命名空间的实现
# Python 中，命名空间的实现是通过字典来实现的。
# 每个模块都有一个字典，用来保存模块中定义的变量、函数、类等实体。
# 当解释器遇到一个标识符时，它会在当前的命名空间中查找该标识符，如果没有找到，
# 则会继续在父级命名空间中查找，直到找到该标识符或者到达最顶层的全局命名空间。
# 如果在全局命名空间中也没有找到该标识符，则会引发 NameError 异常。


# 命名空间的作用
# 命名空间的作用主要有以下几点：
# 1. 避免命名冲突：不同命名空间中的名称可以相同，但不会冲突。
# 2. 隐藏实现细节：通过隐藏实现细节，可以提高代码的可读性和可维护性。
# 3. 实现模块化：通过模块化，可以将复杂的程序分解为多个小模块，每个模块只负责一部分功能，使得程序更容易理解和维护。
# 4. 实现多线程：通过命名空间的隔离，可以实现多线程编程，使得线程之间不会互相干扰。

# 全局命名空间的变量
var1 = 10

def outer_func():
    # 局部命名空间的变量
    var2 = 10
    def inner_func():
        # 嵌套命名空间的变量
        var3 = 10


# 作用域
# 作用域是指变量、函数、类等实体的可访问范围。
# 在一个 python 程序中，直接访问一个变量，会从内到外依次访问所有的作用域直到找到，否则会报未定义的错误

# Python 的四种作用域
# LEGB 规则：Local -> Enclosing -> Global -> Built-in
# 1. Local：指当前函数或模块内部的变量，只能在当前函数或模块内部访问。
# 2. Enclosing：指当前函数或模块内部嵌套的函数或模块的变量，只能在当前函数或模块内部访问。
# 3. Global：指全局作用域的变量，当前模块的全局作用域。
# 4. Built-in：指 Python 内置的变量，可以在整个程序范围内访问。

# 全局变量
g = 10
def outer_func():
    # 局部变量
    l = 20
    def inner_func():
        # 嵌套变量
        n = 30
        print(g, l, n, abs(-40)) # abs() 函数来自内置命名空间
    inner_func()
# 输出结果：10 20 30 40
outer_func()


# global 关键字
# global 关键字用来声明全局变量，使得局部变量可以在全局作用域中访问。
# 当内部作用域想修改全局变量时，需要使用 global 关键字声明。
num = 10
def outer_func():
    global num              # 声明全局变量
    print("修改前的 num 变量值为：", num)  # 输出结果：10
    num = 20
    print("修改后的 num 变量值为：", num)
outer_func() # 输出结果：20
print("全局变量 num 值为：", num)    # 输出结果：20


# nonlocal 关键字
# nonlocal 关键字用来声明外部嵌套作用域的变量，使得内部嵌套作用域可以修改外部嵌套作用域的变量。
# 当内部嵌套作用域想修改外部嵌套作用域的变量时，需要使用 nonlocal 关键字声明。

def outer_func():
    x = 10
    def inner_func():
        nonlocal x       # 声明外部嵌套作用域的变量
        print("修改前的 x 变量值为：", x)
        x = 20
        print("修改后的 x 变量值为：", x)
    inner_func()
    print("外部 x 变量值为：", x)
outer_func()